package com.suxin.utils;

import com.suxin.enums.BaseEnum;

import java.io.File;
import java.net.JarURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author Tang
 * @classname ClassUtil
 * @description [  ]
 * @date 2021/5/6 19:56
 */
public class ClassUtil {

    /**
     * 获取指定接口的实现类
     *
     * @return
     */
    public static List<Class<?>> getAllAssignedClass(Class<?> clz) {
        List<Class<?>> classList = new ArrayList<>(10);
        List<String> fileNames = new ArrayList<>(10);
        if (clz.isInterface()) {
            try {
                Enumeration<URL> resources =
                        Thread.currentThread()
                                .getContextClassLoader()
                                .getResources(BaseEnum.class.getPackage().getName().replace(".", "/"));
                URI toUri = resources.nextElement().toURI();
                File file = new File(toUri);
                if (toUri.toString().startsWith("file")) {
                    // 文件
                    getClassForFile(file, fileNames);
                } else {
                    // jar包
                    getClassForJar(file, fileNames);
                }
                // 创建 class
                getClassList(fileNames, classList, clz);
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 移除自己
            classList.remove(clz);
            return classList;
        }
        throw new RuntimeException("指定的类不是接口!");
    }

    /**
     * class 转换
     *
     * @param list
     * @param classList
     * @param clz
     */
    private static void getClassList(List<String> list, List<Class<?>> classList, Class<?> clz) {
        for (String clazs : list) {
            try {
                Class<?> aClass = Class.forName(clazs);
                if (clz.isAssignableFrom(aClass)) {
                    classList.add(aClass);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 文件读取
     *
     * @param file
     * @param fileNames
     */
    private static void getClassForFile(File file, List<String> fileNames) {
        List<String> list = new ArrayList<>(10);
        for (File item : Objects.requireNonNull(file.listFiles())) {
            if (item.isDirectory()) {
                getClassForFile(item, fileNames);
            } else {
                String path = item.getAbsolutePath();
                fileNames.add(path.substring(path.indexOf("classes") + 8, path.length() - 6)
                        .replace(File.separatorChar + "", "."));
            }
        }
    }

    /**
     * jar 包读取
     *
     * @param file
     * @param fileNames
     */
    private static void getClassForJar(File file, List<String> fileNames) {
        try {
            URL url = file.toURI().toURL();
            JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
            JarFile jarFile = jarURLConnection.getJarFile();
            Enumeration<JarEntry> entries = jarFile.entries();
            String pack = BaseEnum.class.getPackage().getName().replace(".", File.separatorChar + "");
            while (entries.hasMoreElements()) {
                JarEntry jarEntry = entries.nextElement();
                String pathClassName = jarEntry.getName();
                if (pathClassName.startsWith(pack)) {
                    String filePath = pathClassName.replace(File.pathSeparator, ".").substring(0, pathClassName.length() - 6);
                    if (!filePath.endsWith(".")) {
                        fileNames.add(filePath);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}